//=============================================================================
/**
 * @file	gym_dragon.c
 * @brief	ドラゴンジムギミック
 * @author	Nozomu Saito
 *
 * モジュール名：GYM_
 *
 */
//=============================================================================

#include "common.h"
#include "fieldsys.h"
#include "fieldmap_work.h"
#include "system/snd_tool.h"
#include "include/savedata/gimmickwork.h"
#include "../fielddata/build_model/build_model_id.h"

#include "field_gimmick_def.h"
#include "sysflag_def.h"

#include "gym_def.h"

#include "gym_local.h"
#include "gym_init.h"

#include "gym.h"


#define MV_FLOOR_NUM	(3)

#define GRID_SIDE_MAX	(8)
#define GRID_FRBC_MAX	(5)
#define REV_AFFECT_MAX	(24)
#define REV_AFFECT_BC_MAX	(5)
#define FLOOR_W		(3)
#define FLOOR_H		(6)
#define FLOOR_RECT_MAX	(FLOOR_W*FLOOR_H)

#define MV_FLOOR_HEIGHT	(FX32_ONE*ONE_GRID_SIZE*3)

#define TYPE1_W (5)
#define TYPE1_H (7)
#define TYPE1_FRONT_LEN	(4)		//回転ボタンからフロントまでのグリッド数
#define TYPE1_RIGHT_LEN	(2)		//回転ボタンから右側面までのグリッド数

#define TYPE2_W (4)
#define TYPE2_H (8)
#define TYPE2_FRONT_LEN	(5)		//回転ボタンからフロントまでのグリッド数
#define TYPE2_RIGHT_LEN	(2)		//回転ボタンから右側面までのグリッド数

#define MOVE_VAL	(FX32_ONE*8)
#define MOVE_COUNT	(2)

#define REV_VAL	(0x400)
#define REV_COUNT	(16)

#define HIT_NONE	(0xff)

#define REV_UNIT	(0x100)	//回転ヒット判定に使うラジアン単位

typedef enum{
	FLOOR_TYPE_1,
	FLOOR_TYPE_2,
}FLOOR_TYPE;

typedef enum{
	BTN_TYPE_L,
	BTN_TYPE_R,
}BTN_TYPE;

typedef enum{
	EVT_TYPE_NONE,
	EVT_TYPE_REV,
	EVT_TYPE_SHIFT_L,
	EVT_TYPE_SHIFT_R,
}EVT_TYPE;

typedef enum{
	SEQ_SHIFT_INIT,
	SEQ_SHIFT_CHECK,
	SEQ_SHIFT_ANM,
	SEQ_SHIFT_UPDATE,
	SEQ_HIT_ACTION_SET,
	SEQ_HIT_ACTION,
	SEQ_SHIFT_REVERS,
	SEQ_SHIFT_END,

	SEQ_REV_CHECK,
	SEQ_REV_ANM,
	SEQ_REV_NG_ANM,
	SEQ_REV_REVERS,
	SEQ_REV_END,

}EVENT_SEQ;

typedef enum{
	SHIFT_DIR_X_PLUS,
	SHIFT_DIR_Z_PLUS,
	SHIFT_DIR_X_MINUS,
	SHIFT_DIR_Z_MINUS,
}SHIFT_DIR;

typedef enum{
	REV_NONE,
	REV_NG,
	REV_OK,
}REV_RC;

//床の基準方向はZ+方向とする

typedef struct GRID_POS_tag
{
	int X;
	int Z;
}GRID_POS;

typedef struct MV_FLOOR_tag
{
	FLOOR_TYPE Type;				//床タイプ
	u8 GridW;				//床横幅
	u8 GridH;				//床縦幅
	u8 RevState;			//現在の床の回転状況
	u8 MdlIdx;
	GRID_POS RevBtnPos;		//回転ボタン位置
	GRID_POS ShiftBtnPosL;	//平行移動ボタン位置（床が無回転で床の基準方向がZ+のとき左側にあるボタン）
	GRID_POS ShiftBtnPosR;	//平行移動ボタン位置（床が無回転で床の基準方向がZ+のとき右側にあるボタン）
	GRID_POS BasePos;			//床基準位置
	//移動床周辺のグリッド情報
	GRID_POS SideLeft[GRID_SIDE_MAX];
	GRID_POS SideRight[GRID_SIDE_MAX];
	GRID_POS SideFront[GRID_FRBC_MAX];
	GRID_POS SideBack[GRID_FRBC_MAX];
	GRID_POS RevAffectGrid[REV_AFFECT_MAX];
	GRID_POS RevAffBackGrid[REV_AFFECT_BC_MAX];
	GRID_POS Floor[FLOOR_RECT_MAX];
}MV_FLOOR;

typedef struct DRAGON_GYM_TEMP_WORK_tag
{
	FIELDSYS_WORK *fsys;
	MV_FLOOR	MvFloor[MV_FLOOR_NUM];
}DRAGON_GYM_TEMP_WORK;


typedef struct {
	EVENT_SEQ Seq;							///<シーケンス保持ワーク
	GRID_POS SideTemp[GRID_SIDE_MAX];
	GRID_POS OrgPos;
	u8 FloorIdx;		//発動する移動床のインデックス
	u8 AnmCount;
	u8 AnmCountMax;
	u8 MoveCount;
	EVT_TYPE EventType;
	SHIFT_DIR ShiftDir;
	VecFx32 MoveVec;
	int Rev;
	int LimitRev;
	int BaseRev;
	FIELDSYS_WORK * fsys;
}EVENT_GYM_WORK;

static void SetUpMvFloorData(	const u8 inIdx, const u8 inRevState,
								const u16 inX, const u16 inZ,
								MV_FLOOR *outFloor	);
static void CalcRotPos(const u8 inState, const u16 inX, const u16 inZ, const GRID_POS *inPos, GRID_POS *outPos);
static void AddX(const int inX, const u8 inLoop, GRID_POS *outPos);
static void AddZ(const int inZ, const u8 inLoop, GRID_POS *outPos);
static void CalcRot(const u8 inState, const u16 inX, const u16 inZ, MV_FLOOR *outFloor);
static EVT_TYPE CheckEvent(const DRAGON_GYM_TEMP_WORK *inTempWork,
		const u16 inX, const u16 inZ, u8 *outIdx);
static BOOL SetEvent(const DRAGON_GYM_TEMP_WORK *inTempWork, const u16 inX, const u16 inZ);
static void CopySideInfo(const MV_FLOOR *inFloor, EVENT_GYM_WORK *egw);
static void AddSideTmpInfo(const int inLoop, EVENT_GYM_WORK *egw);
static SHIFT_DIR GetShiftDir(const inRev, const BTN_TYPE inBtnType);
static void GetMoveVal(const SHIFT_DIR inShiftDir, VecFx32 *outVec);
static u8 CheckHit(FIELDSYS_WORK * fsys, const u8 inLoop, const GRID_POS *inPosArray);

static BOOL ShiftFloorEvent( GMEVENT_CONTROL * event );
static BOOL RevFloorEvent( GMEVENT_CONTROL * event );

static REV_RC CheckHitRev(FIELDSYS_WORK * fsys, MV_FLOOR *floor, u16 *outRot);
static u16 GetRevHitVal( FIELDSYS_WORK * fsys, MV_FLOOR *floor );
static u16 CheckAffHit(FIELDSYS_WORK * fsys, const u8 inLoop, const GRID_POS *inPosArray, const u8 *inRevInfo );

static void ShiftTcb( TCB_PTR tcb, void *work );

#ifdef PM_DEBUG
static void DebugPrint(MV_FLOOR *floor);
static BOOL DebugFloorEvent( GMEVENT_CONTROL * event );
#endif	//PM_DEBUG


//リフト周辺の回転情報
static const u8 RevInfoFront1[] = {
	10,10,13,18,25,38,51,
	64,64,23,28,35,45,55,
};

static const u8 RevInfoFront2[] = {
	8 ,9 ,10,14,19,26,37,51,
	64,17,19,23,28,35,46,55,
	64,64,64,30,35,41,49,57,
};

static const u8 RevInfoBack1[] = {
	64,64,64,64,42,
};

static const u8 RevInfoBack2[] = {
	64,20,30,46,
};




//---------------------------------------------------------------------------
/**
 * @brief	ドラゴンジム:セットアップ
 *
 * @param	fsys	フィールドシステムポインタ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
void GYM_SetupDragonGym(FIELDSYS_WORK *fsys)
{
	int i;
	GIMMICKWORK *work;
	DRAGON_GYM_WORK *dragon_gym_work;
	DRAGON_GYM_TEMP_WORK *dragon_temp;

	u32 mdl_id_array[MV_FLOOR_NUM] = { BMID_ROOM_GYM08LIFTA, BMID_ROOM_GYM08LIFTB, BMID_ROOM_GYM08LIFTA };

	//ここでギミックワークの中身を見る
	work = SaveData_GetGimmickWork(GameSystem_GetSaveData(fsys));
	dragon_gym_work = (DRAGON_GYM_WORK*)GIMMICKWORK_Get(work, FLD_GIMMICK_DRAGON_GYM);

	//ドラゴンジム専用ワークをアロケートして、フィールドマップ汎用ワークポインタにあてる
	fsys->fldmap->Work = sys_AllocMemory(HEAPID_FIELD, sizeof(DRAGON_GYM_TEMP_WORK));
	//初期化
	MI_CpuClear8(fsys->fldmap->Work, sizeof(DRAGON_GYM_TEMP_WORK));
	dragon_temp = fsys->fldmap->Work;
	dragon_temp->fsys = fsys;

	for(i=0;i<MV_FLOOR_NUM;i++){
		VecFx32 vec = {0,MV_FLOOR_HEIGHT,0};
		VecFx32 rot = {0,0,0};
		rot.y = - (0x4000 * dragon_gym_work->RevState[i]);
		//移動床の作成
		vec.x = dragon_gym_work->FloorX[i] * ONE_GRID_SIZE*FX32_ONE + ONE_GRID_SIZE*FX32_ONE/2;
		vec.z = dragon_gym_work->FloorZ[i] * ONE_GRID_SIZE*FX32_ONE + ONE_GRID_SIZE*FX32_ONE/2;
		dragon_temp->MvFloor[i].MdlIdx = M3DO_SetMap3DObjExp(fsys->Map3DObjExp,
									mdl_id_array[i],
									&vec, &rot,
									fsys->field_3d_anime );//<リフト

		//座標関連のセットアップ
		SetUpMvFloorData( i, dragon_gym_work->RevState[i],
				dragon_gym_work->FloorX[i],
				dragon_gym_work->FloorZ[i],
				&dragon_temp->MvFloor[i]	);
#ifdef PM_DEBUG
		//デバッグ 座標表示
		DebugPrint(&dragon_temp->MvFloor[i]);
#endif
	}

}

//---------------------------------------------------------------------------
/**
 * @brief	ドラゴンジム:終了処理
 *
 * @param	fsys	フィールドシステムポインタ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
void GYM_EndDragonGym(FIELDSYS_WORK *fsys)
{
	DRAGON_GYM_TEMP_WORK *dragon_temp;
	dragon_temp = (DRAGON_GYM_TEMP_WORK *)fsys->fldmap->Work;
	sys_FreeMemoryEz(dragon_temp);
	fsys->fldmap->Work = NULL;
}

//---------------------------------------------------------------------------
/**
 * @brief	ドラゴンジム:イベントチェック
 *
 * @param	fsys	フィールドシステムポインタ
 *
 * @return	BOOL	TRUE:リフトあり		FALSE:リフト無し
 */
//---------------------------------------------------------------------------
BOOL GYM_CheckDragonGymEvt(FIELDSYS_WORK *fsys)
{
	BOOL rc;
	DRAGON_GYM_TEMP_WORK *dragon_temp;

	//ギミックワークを見る
	{
		int id;
		GIMMICKWORK *work;

		//ギミックワーク取得
		work = SaveData_GetGimmickWork(GameSystem_GetSaveData(fsys));
		//ギミックコードを取得
		id = GIMMICKWORK_GetAssignID(work);

		if (id != FLD_GIMMICK_DRAGON_GYM){
			return FALSE;					//ドラゴンジムギミック無し
		}
	}

	dragon_temp = (DRAGON_GYM_TEMP_WORK *)fsys->fldmap->Work;
	if (dragon_temp == NULL){
		return FALSE;
	}

	{
		int x,z;
		//踏んでる座標を取得
		x = Player_NowGPosXGet(fsys->player);
		z = Player_NowGPosZGet(fsys->player);
		rc = SetEvent(dragon_temp, x, z);
	}
	return rc;
}

//---------------------------------------------------------------------------
/**
 * @brief	ドラゴンジム:当たり判定
 *
 * @param	fsys		フィールドシステムポインタ
 * @param	inGridX		グリッドX座標
 * @param	inGridZ		グリッドZ座標
 * @param	inHeight	高さ
 * @param	outHit		判定結果	TRUE:ヒット	FALSE:ヒットしてない
 *
 * @return	BOOL		TRUE:このあと通常当たり判定を行わない	FALSE:通常当たり判定を行う
 */
//---------------------------------------------------------------------------
BOOL GYM_HitCheckDragonGym(	FIELDSYS_WORK *fsys,
							const int inGridX, const int inGridZ,
							const fx32 inHeight, BOOL *outHit	)
{

	int i,j;
	DRAGON_GYM_TEMP_WORK *dragon_temp;
	dragon_temp = (DRAGON_GYM_TEMP_WORK *)fsys->fldmap->Work;

	//リフトチェック
	for(i=0;i<MV_FLOOR_NUM;i++){
		MV_FLOOR *floor;
		floor = &dragon_temp->MvFloor[i];
		for (j=0;j<FLOOR_RECT_MAX;j++){
			if ((floor->Floor[j].X == inGridX) &&
				(floor->Floor[j].Z == inGridZ) ){
				*outHit = FALSE;	//リフトの上
				return TRUE;
			}
		}
	}

	//マグマチェック　踏んだアトリビュートがマグマならば通行不可
	{
		u8 attr;
		//アトリビュートを調べる
		attr = GetAttributeLSB(fsys, inGridX, inGridZ);
		if ( MATR_IsMagma(attr) ){
			*outHit = TRUE;		//通行不可
			return TRUE;
		}
	}

	return FALSE;	//通常当たり判定を実行
}

//---------------------------------------------------------------------------
/**
 * @brief	床データセットアップ
 *
 * @param	inIdx			床インデックス
 * @param	inRevState		回転状態
 * @param	inX				グリッドX座標
 * @param	inZ				グリッドZ座標
 * @param	outFloor		床データポインタ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
static void SetUpMvFloorData(	const u8 inIdx, const u8 inRevState,
								const u16 inX, const u16 inZ,
								MV_FLOOR *outFloor	)
{
	GRID_POS base;

	//回転ボタン位置セット
	outFloor->RevBtnPos.X = inX;
	outFloor->RevBtnPos.Z = inZ;
	//平行移動ボタン位置セット
	outFloor->ShiftBtnPosL.X = inX+1;
	outFloor->ShiftBtnPosL.Z = inZ;
	outFloor->ShiftBtnPosR.X = inX-1;
	outFloor->ShiftBtnPosR.Z = inZ;
	//モデル中心座標セット
	outFloor->BasePos.X = inX;
	outFloor->BasePos.Z = inZ;
	//作成する床形状別処理
	if (inIdx != 1){		//第1・第3関門の移動床
		//タイプセット
		outFloor->Type = FLOOR_TYPE_1;
		//横幅設定
		outFloor->GridW = TYPE1_W;
		//縦幅設定
		outFloor->GridH = TYPE1_H;
		//床周辺グリッド座標のセット
		{	//床が無回転で、Z+の方向を向いているとして・・・
			int i,j;
			base.X = inX;
			base.Z = inZ;
			base.X+=3;
			base.Z-=2;
			//左側面座標セット
			for(i=0;i<TYPE1_H;i++){
				outFloor->SideLeft[i] = base;
				outFloor->SideLeft[i].Z += i;
			}

			base.X = inX;
			base.Z = inZ;
			base.X-=3;
			base.Z-=2;
			//右側面座標セット
			for(i=0;i<TYPE1_H;i++){
				outFloor->SideRight[i] = base;
				outFloor->SideRight[i].Z += i;
			}

			base.X = inX;
			base.Z = inZ;
			base.X-=2;
			base.Z+=5;
			//前方座標セット
			for(i=0;i<TYPE1_W;i++){
				outFloor->SideFront[i] = base;
				outFloor->SideFront[i].X += i;
			}

			base.X = inX;
			base.Z = inZ;
			base.X-=2;
			base.Z-=3;
			//後方座標セット
			for(i=0;i<TYPE1_W;i++){
				outFloor->SideBack[i] = base;
				outFloor->SideBack[i].X += i;
			}

			//回転に影響する(かもしれない)場所の座標セット(検査順にセット)
			for (i=0;i<TYPE1_FRONT_LEN-TYPE1_RIGHT_LEN;i++){
				base.X = inX-4;
				base.Z = inZ+TYPE1_FRONT_LEN;
				base.X -= i;
				for(j=0;j<TYPE1_H;j++){
					outFloor->RevAffectGrid[i*TYPE1_H+j] = base;
					outFloor->RevAffectGrid[i*TYPE1_H+j].Z -= j;
				}
			}

			//回転によって後部がヒットする(かもしれない)場所の座標セット(検査順にセット)
			for (i=0;i<outFloor->GridW;i++){
				base.X = inX+3;
				base.Z = inZ-2;
				outFloor->RevAffBackGrid[i] = base;
				outFloor->RevAffBackGrid[i].Z += i;
			}
		}
	}else{					//第2関門の移動床
		//タイプセット
		outFloor->Type = FLOOR_TYPE_2;
		//横幅設定
		outFloor->GridW = TYPE2_W;
		//縦幅設定
		outFloor->GridH = TYPE2_H;
		//床周辺グリッド座標のセット
		{	//床が無回転で、Z+の方向を向いているとして・・・
			int i,j;
			base.X = inX;
			base.Z = inZ;
			base.X+=2;
			base.Z-=2;
			//左側面座標セット
			for(i=0;i<TYPE2_H;i++){
				outFloor->SideLeft[i] = base;
				outFloor->SideLeft[i].Z += i;
			}

			base.X = inX;
			base.Z = inZ;
			base.X-=3;
			base.Z-=2;
			//右側面座標セット
			for(i=0;i<TYPE2_H;i++){
				outFloor->SideRight[i] = base;
				outFloor->SideRight[i].Z += i;
			}

			base.X = inX;
			base.Z = inZ;
			base.X-=2;
			base.Z+=6;
			//前方座標セット
			for(i=0;i<TYPE2_W;i++){
				outFloor->SideFront[i] = base;
				outFloor->SideFront[i].X += i;
			}

			base.X = inX;
			base.Z = inZ;
			base.X-=2;
			base.Z-=3;
			//後方座標セット
			for(i=0;i<TYPE2_W;i++){
				outFloor->SideBack[i] = base;
				outFloor->SideBack[i].X += i;
			}

			//回転に影響する(かもしれない)場所の座標セット(検査順にセット)
			for (i=0;i<TYPE2_FRONT_LEN-TYPE2_RIGHT_LEN;i++){
				base.X = inX-4;
				base.Z = inZ+TYPE2_FRONT_LEN;
				base.X-=i;
				for(j=0;j<TYPE2_H;j++){
					outFloor->RevAffectGrid[i*TYPE2_H+j] = base;
					outFloor->RevAffectGrid[i*TYPE2_H+j].Z -= j;
				}
			}

			//回転によって後部がヒットする(かもしれない)場所の座標セット(検査順にセット)
			for (i=0;i<outFloor->GridW;i++){
				base.X = inX+3;
				base.Z = inZ-2;
				outFloor->RevAffBackGrid[i] = base;
				outFloor->RevAffBackGrid[i].Z += i;
			}
		}
	}

	//床データ作成
	{
		int i,j;
		base.X = inX-1;
		base.Z = inZ-1;
		for(i=0;i<FLOOR_H;i++){
			for(j=0;j<FLOOR_W;j++){
				outFloor->Floor[i*FLOOR_W+j].X = base.X + j;
				outFloor->Floor[i*FLOOR_W+j].Z = base.Z + i;
			}
		}
	}

	//回転ステートセット
	outFloor->RevState = inRevState;
	//回転ステートに応じた回転を全座標にかける
	CalcRot(inRevState, inX, inZ, outFloor);
}

//---------------------------------------------------------------------------
/**
 * @brief	床データセットアップ
 *
 * @param	inState			ステート
 * @param	inX				グリッドX座標
 * @param	inZ				グリッドZ座標
 * @param	inPos			グリッド位置
 * @param	outPos			グリッド位置
 *
 * @return	none
 */
//---------------------------------------------------------------------------
static void CalcRotPos(const u8 inState, const u16 inX, const u16 inZ, const GRID_POS *inPos, GRID_POS *outPos)
{
	int fix_x, fix_z;
	fix_x = inPos->X - inX;
	fix_z = inPos->Z - inZ;

	switch(inState){
	case FLOOR_REV_90:		//90度回転
		outPos->X = -fix_z;
		outPos->Z = fix_x;
		break;
	case FLOOR_REV_180:		//180度回転
		outPos->X = -fix_x;
		outPos->Z = -fix_z;
		break;
	case FLOOR_REV_270:		//270度回転
		outPos->X = fix_z;
		outPos->Z = -fix_x;
		break;
	default:
		return;
	}

	outPos->X += inX;
	outPos->Z += inZ;
}

//---------------------------------------------------------------------------
/**
 * @brief	加算X
 *
 * @param	inX			グリッドX座標
 * @param	inLoop		ループ回数
 * @param	outPos		出力グリッド位置
 *
 * @return	none
 */
//---------------------------------------------------------------------------
static void AddX(const int inX, const u8 inLoop, GRID_POS *outPos)
{
	int i;
	for(i=0;i<inLoop;i++){
		outPos[i].X += inX;
	}
}

//---------------------------------------------------------------------------
/**
 * @brief	加算Z
 *
 * @param	inZ			グリッドZ座標
 * @param	inLoop		ループ回数
 * @param	outPos		出力グリッド位置
 *
 * @return	none
 */
//---------------------------------------------------------------------------
static void AddZ(const int inZ, const u8 inLoop, GRID_POS *outPos)
{
	int i;
	for(i=0;i<inLoop;i++){
		outPos[i].Z += inZ;
	}
}

//---------------------------------------------------------------------------
/**
 * @brief	回転計算
 *
 * @param	inState		ステート
 * @param	inX			グリッドX座標
 * @param	inZ			グリッドZ座標
 * @param	outFloor	フロアデータ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
static void CalcRot(const u8 inState, const u16 inX, const u16 inZ, MV_FLOOR *outFloor)
{
	int i;
	int loop;
	u8 w,h;

	if ( outFloor->Type == FLOOR_TYPE_1 ){
		loop = (TYPE1_FRONT_LEN-TYPE1_RIGHT_LEN)*TYPE1_H;
		w = TYPE1_W;
		h = TYPE1_H;
	}else{
		loop = (TYPE2_FRONT_LEN-TYPE2_RIGHT_LEN)*TYPE2_H;
		w = TYPE2_W;
		h = TYPE2_H;
	}

	//ボタン回転
	CalcRotPos(inState, inX, inZ, &outFloor->ShiftBtnPosL, &outFloor->ShiftBtnPosL);
	CalcRotPos(inState, inX, inZ, &outFloor->ShiftBtnPosR, &outFloor->ShiftBtnPosR);
	//周辺チェックグリッド回転
	//左側面座標
	for(i=0;i<h;i++){
		CalcRotPos(inState, inX, inZ, &outFloor->SideLeft[i], &outFloor->SideLeft[i]);
	}

	//右側面座標
	for(i=0;i<h;i++){
		CalcRotPos(inState, inX, inZ, &outFloor->SideRight[i], &outFloor->SideRight[i]);
	}

	//前方座標セット
	for(i=0;i<w;i++){
		CalcRotPos(inState, inX, inZ, &outFloor->SideFront[i], &outFloor->SideFront[i]);
	}

	//後方座標セット
	for(i=0;i<w;i++){
		CalcRotPos(inState, inX, inZ, &outFloor->SideBack[i], &outFloor->SideBack[i]);
	}

	//回転に影響する(かもしれない)場所の座標セット
	for (i=0;i<loop;i++){
		CalcRotPos(inState, inX, inZ, &outFloor->RevAffectGrid[i], &outFloor->RevAffectGrid[i]);
	}
	//回転に影響する(かもしれない)場所の座標セット
	for (i=0;i<w;i++){
		CalcRotPos(inState, inX, inZ, &outFloor->RevAffBackGrid[i], &outFloor->RevAffBackGrid[i]);
	}
	//歩ける範囲(床)セット
	for (i=0;i<FLOOR_RECT_MAX;i++){
		CalcRotPos(inState, inX, inZ, &outFloor->Floor[i], &outFloor->Floor[i]);
	}
}

//---------------------------------------------------------------------------
/**
 * @brief	チェック
 *
 * @param	inTempWork	ワーク
 * @param	inX			グリッドX座標
 * @param	inZ			グリッドZ座標
 * @param	outIdx	データ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
static EVT_TYPE CheckEvent(const DRAGON_GYM_TEMP_WORK *inTempWork, const u16 inX, const u16 inZ, u8 *outIdx)
{
	u8 i;
	for(i=0;i<MV_FLOOR_NUM;i++){
		if ( (inTempWork->MvFloor[i].RevBtnPos.X==inX)&&
				(inTempWork->MvFloor[i].RevBtnPos.Z==inZ) ){
			*outIdx = i;
			return EVT_TYPE_REV;
		}else if((inTempWork->MvFloor[i].ShiftBtnPosL.X==inX)&&
				(inTempWork->MvFloor[i].ShiftBtnPosL.Z==inZ) ){
			*outIdx = i;
			return EVT_TYPE_SHIFT_L;
		}else if((inTempWork->MvFloor[i].ShiftBtnPosR.X==inX)&&
				(inTempWork->MvFloor[i].ShiftBtnPosR.Z==inZ) ){
			*outIdx = i;
			return EVT_TYPE_SHIFT_R;
		}
	}
	return EVT_TYPE_NONE;
}

//---------------------------------------------------------------------------
/**
 * @brief	イベントセット
 *
 * @param	inTempWork
 * @param	inX			グリッドX座標
 * @param	inZ			グリッドZ座標
 *
 * @return	none
 */
//---------------------------------------------------------------------------
static BOOL SetEvent(const DRAGON_GYM_TEMP_WORK *inTempWork, const u16 inX, const u16 inZ)
{
	BOOL rc;
	EVT_TYPE evt_type;
	u8 idx;
	EVENT_GYM_WORK * egw;

	evt_type = CheckEvent(inTempWork, inX, inZ, &idx);

	if (evt_type == EVT_TYPE_NONE){
		return FALSE;
	}

	//イベントセット
	egw = sys_AllocMemoryLo(HEAPID_WORLD, sizeof(EVENT_GYM_WORK));
	egw->fsys = inTempWork->fsys;
	egw->Seq = 0;
	egw->FloorIdx = idx;
	egw->EventType = evt_type;

	rc = FALSE;

	switch(evt_type){
	case EVT_TYPE_REV:

		egw->Seq = SEQ_REV_CHECK;
		OS_Printf("回転ボタンを押下\n");
		//ゴンドラ回転ＳＥ
		Snd_SePlay(SEQ_SE_GS_GONDORA_IDOU);
		FieldEvent_Set(inTempWork->fsys, RevFloorEvent, egw);
		rc = TRUE;
		break;
	case EVT_TYPE_SHIFT_L:
		egw->Seq = SEQ_SHIFT_INIT;
		egw->AnmCount = 0;
		egw->AnmCountMax = inTempWork->MvFloor[idx].GridW;
		egw->ShiftDir = GetShiftDir(inTempWork->MvFloor[idx].RevState, BTN_TYPE_L);
		GetMoveVal(egw->ShiftDir, &egw->MoveVec);
		OS_Printf("左のボタンを押下\n");
		//ゴンドラ移動ＳＥ
		Snd_SePlay(SEQ_SE_GS_GONDORA_IDOU);
		FieldEvent_Set(inTempWork->fsys, ShiftFloorEvent, egw);
		rc = TRUE;
		break;
	case EVT_TYPE_SHIFT_R:
		egw->Seq = SEQ_SHIFT_INIT;
		egw->AnmCount = 0;
		egw->AnmCountMax = inTempWork->MvFloor[idx].GridW;
		egw->ShiftDir = GetShiftDir(inTempWork->MvFloor[idx].RevState, BTN_TYPE_R);
		GetMoveVal(egw->ShiftDir, &egw->MoveVec);
		OS_Printf("右のボタンを押下\n");
		//ゴンドラ移動ＳＥ
		Snd_SePlay(SEQ_SE_GS_GONDORA_IDOU);
		FieldEvent_Set(inTempWork->fsys, ShiftFloorEvent, egw);
		rc = TRUE;
		break;
	default:
		break;
	}

	return rc;
}

//---------------------------------------------------------------------------
/**
 * @brief	移動方向の隣接グリッド情報をコピー
 *
 * @param	inFloor		フロアデータ
 * @param	egw			ワーク
 *
 * @return	none
 */
//---------------------------------------------------------------------------
static void CopySideInfo(const MV_FLOOR *inFloor, EVENT_GYM_WORK *egw)
{
	int i;
	//イベントタイプをみて、コピーする情報を決定
	switch(egw->EventType){
	case EVT_TYPE_SHIFT_L:
		for(i=0;i<inFloor->GridH;i++){
			egw->SideTemp[i] = inFloor->SideLeft[i];
		}
		break;
	case EVT_TYPE_SHIFT_R:
		for(i=0;i<inFloor->GridH;i++){
			egw->SideTemp[i] = inFloor->SideRight[i];
		}
		break;
	default:
		break;
	}
}

//---------------------------------------------------------------------------
/**
 * @brief	コピーデータ更新
 *
 * @param	inLoop		ループ回数
 * @param	egw			ワーク
 *
 * @return	none
 */
//---------------------------------------------------------------------------
static void AddSideTmpInfo(const int inLoop, EVENT_GYM_WORK *egw)
{
	switch(egw->ShiftDir){
	case SHIFT_DIR_X_PLUS:
		AddX(1, inLoop, egw->SideTemp);
		break;
	case SHIFT_DIR_Z_PLUS:
		AddZ(1, inLoop, egw->SideTemp);
		break;
	case SHIFT_DIR_X_MINUS:
		AddX(-1, inLoop, egw->SideTemp);
		break;
	case SHIFT_DIR_Z_MINUS:
		AddZ(-1, inLoop, egw->SideTemp);
		break;
	}
}

//---------------------------------------------------------------------------
/**
 * @brief	回転ステートと踏んだボタンから、進行方向を取得する
 *
 * @param	inRev			回転ステート
 * @param	inBtnType		ボタンタイプ
 *
 * @return	SHIFT_DIR
 */
//---------------------------------------------------------------------------
static SHIFT_DIR GetShiftDir(const inRev, const BTN_TYPE inBtnType)
{
	SHIFT_DIR dir;
	if (inBtnType == BTN_TYPE_L){
		dir = SHIFT_DIR_X_PLUS;
	}else{
		dir = SHIFT_DIR_X_MINUS;
	}

	dir = (dir + inRev) % 4;

	return dir;
}

//---------------------------------------------------------------------------
/**
 * @brief	進む方向の加算値を取得
 *
 * @param	inShiftDir		シフト方向
 * @param	outVec			格納バッファ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
static void GetMoveVal(const SHIFT_DIR inShiftDir, VecFx32 *outVec)
{
	outVec->x = 0;
	outVec->y = 0;
	outVec->z = 0;

	switch(inShiftDir){
	case SHIFT_DIR_X_PLUS:
		outVec->x = MOVE_VAL;
		break;
	case SHIFT_DIR_Z_PLUS:
		outVec->z = MOVE_VAL;
		break;
	case SHIFT_DIR_X_MINUS:
		outVec->x = -MOVE_VAL;
		break;
	case SHIFT_DIR_Z_MINUS:
		outVec->z = -MOVE_VAL;
		break;
	}
}

//---------------------------------------------------------------------------
/**
 * @brief	ヒットチェック
 *
 * @param	fsys		フィールドシステムポインタ
 * @param	inLoop		ループ回数
 * @param	inPosArray	グリッド位置配列データポインタ
 *
 * @return	u8		ヒットしたインデックス
 */
//---------------------------------------------------------------------------
static u8 CheckHit(FIELDSYS_WORK * fsys, const u8 inLoop, const GRID_POS *inPosArray)
{
	int i;
	u8 idx;
	BOOL rc;
	u8 attr;

	idx = HIT_NONE;
	for(i=0;i<inLoop;i++){
		rc = GetHitAttr(fsys, inPosArray[i].X, inPosArray[i].Z);
		if (rc){
			idx = i;
			break;
		}
		//マグマアトリビュートでなければ、リフトは動けないものとする
		attr = GetAttributeLSB(fsys, inPosArray[i].X, inPosArray[i].Z);
		if ( !MATR_IsMagma(attr) ){
			idx = i;
			break;
		}
	}

	return idx;
}

//---------------------------------------------------------------------------
/**
 * @brief	ヒットチェック
 *
 * @param	fsys			フィールドシステムポインタ
 * @param	inLoop			ループ回数
 * @param	inPosArray		グリッド位置配列データポインタ
 * @param	inRevInfo		回転情報
 *
 * @return	u8		ヒットしたインデックスの回転限界
 */
//---------------------------------------------------------------------------
static u16 CheckAffHit(FIELDSYS_WORK * fsys, const u8 inLoop, const GRID_POS *inPosArray, const u8 *inRevInfo )
{
	int i;
	u16 rot;
	BOOL rc;

	rot = 0x4000;

	for(i=0;i<inLoop;i++){
		rc = GetHitAttr(fsys, inPosArray[i].X, inPosArray[i].Z);
		if (!rc){
			u8 attr;
			//マグマアトリビュートでなければ、リフトは動けないものとする
			attr = GetAttributeLSB(fsys, inPosArray[i].X, inPosArray[i].Z);
			rc = !MATR_IsMagma(attr);
		}
		if (rc){
			//ヒットしたインデックスの回転限界を調べる
			if (inRevInfo[i] * REV_UNIT < 0x4000 ){
				rot = inRevInfo[i] * REV_UNIT;
				break;
			}
		}
	}

	return rot;
}

//---------------------------------------------------------------------------
/**
 * @brief	シフトイベント
 *
 * @param	event		イベントポインタ
 *
 * @return	BOOL		TRUEで終了
 */
//---------------------------------------------------------------------------
static BOOL ShiftFloorEvent( GMEVENT_CONTROL * event )
{
	DRAGON_GYM_TEMP_WORK *dragon_temp;
	FIELDSYS_WORK * fsys = FieldEvent_GetFieldSysWork(event);
	EVENT_GYM_WORK * egw = FieldEvent_GetSpecialWork(event);

	dragon_temp = (DRAGON_GYM_TEMP_WORK *)fsys->fldmap->Work;

	switch(egw->Seq){
	case SEQ_SHIFT_INIT:
		//移動方向の隣接グリッド情報をコピー
		CopySideInfo( &dragon_temp->MvFloor[egw->FloorIdx], egw );

		//TCB作成（フィールドOBJより速く処理されるようにプライオリティを決定する）
		TCB_Add(ShiftTcb, egw, 0);
		egw->Seq = SEQ_SHIFT_CHECK;
		break;
	case SEQ_SHIFT_UPDATE:
		//全座標更新
		{
			MV_FLOOR *floor;
			int x,z;
			M3DO_PTR ptr;
			int entry;
			VecFx32 lift_vec;
			FIELD_OBJ_PTR fldobj;

			entry = dragon_temp->MvFloor[egw->FloorIdx].MdlIdx;
			ptr = M3DO_GetMap3DObjData(fsys->Map3DObjExp, entry);
			lift_vec = M3DO_GetGlobalVec(ptr);

			x = lift_vec.x/(ONE_GRID_SIZE*FX32_ONE);
			z = lift_vec.z/(ONE_GRID_SIZE*FX32_ONE);
			OS_Printf("更新座標：%d, %d\n", x, z);
			floor = &dragon_temp->MvFloor[egw->FloorIdx];
			{
				DRAGON_GYM_WORK *dragon_gym_work;
				GIMMICKWORK *work;
				work = SaveData_GetGimmickWork(GameSystem_GetSaveData(fsys));
				dragon_gym_work = (DRAGON_GYM_WORK*)GIMMICKWORK_Get(work, FLD_GIMMICK_DRAGON_GYM);
				dragon_gym_work->FloorX[ egw->FloorIdx ] = x;
				dragon_gym_work->FloorZ[ egw->FloorIdx ] = z;
			}
			SetUpMvFloorData(egw->FloorIdx, floor->RevState,
								x, z,
								floor	);
#ifdef PM_DEBUG
			//デバッグ表示
			DebugPrint(floor);
#endif
		}
		egw->Seq = SEQ_SHIFT_END;
		break;
	case SEQ_SHIFT_END:
		//SEストップ
		Snd_SeStopBySeqNo(SEQ_SE_GS_GONDORA_IDOU, 0);
		//ワーク解放
		sys_FreeMemoryEz(egw);
		return TRUE;
		break;
	}

	return FALSE;
}

//---------------------------------------------------------------------------
/**
 * @brief	回転イベント
 *
 * @param	event		イベントポインタ
 *
 * @return	BOOL		TRUEで終了
 */
//---------------------------------------------------------------------------
static BOOL RevFloorEvent( GMEVENT_CONTROL * event )
{
	DRAGON_GYM_TEMP_WORK *dragon_temp;
	FIELDSYS_WORK * fsys = FieldEvent_GetFieldSysWork(event);
	EVENT_GYM_WORK * egw = FieldEvent_GetSpecialWork(event);

	dragon_temp = (DRAGON_GYM_TEMP_WORK *)fsys->fldmap->Work;

	switch(egw->Seq){
	case SEQ_REV_CHECK:
		{
			u16 rot;
			REV_RC rev_rc;
			MV_FLOOR *floor;
			floor = &dragon_temp->MvFloor[egw->FloorIdx];
			egw->MoveCount = 0;
			//回転影響のあるグリッドをすべてチェック
			rev_rc = CheckHitRev(fsys, floor, &rot);
			if (rev_rc == REV_OK){
				//回転できるので、アニメ開始
				egw->Seq = SEQ_REV_ANM;
			}else if( rev_rc == REV_NG ){
				M3DO_PTR ptr;
				int entry;
				VecFx32 *rev;
				entry = dragon_temp->MvFloor[egw->FloorIdx].MdlIdx;
				ptr = M3DO_GetMap3DObjData(fsys->Map3DObjExp, entry);
				rev = M3DO_GetRotateVecPtr(ptr);
				egw->LimitRev = rot;
				egw->BaseRev = rev->y;
				egw->Rev = 0;
				//90度回転できないけど途中まで回転できるアニメ開始
				egw->Seq = SEQ_REV_NG_ANM;
				OS_Printf("途中まで回転\n");
				//ぶつかったＳＥ
				Snd_SePlay(SEQ_SE_GS_GONDORA_KABEHIT);
			}else{
				//回転できない
				egw->Seq = SEQ_REV_END;
				OS_Printf("まったく回転しない\n");
			}
		}
		break;
	case SEQ_REV_ANM:		//回転アニメ
		{
			M3DO_PTR ptr;
			int entry;
			VecFx32 *rev;

			entry = dragon_temp->MvFloor[egw->FloorIdx].MdlIdx;
			ptr = M3DO_GetMap3DObjData(fsys->Map3DObjExp, entry);
			rev = M3DO_GetRotateVecPtr(ptr);
			rev->y += (-REV_VAL);
		}

		if (++egw->MoveCount >= REV_COUNT){
			MV_FLOOR *floor;
			floor = &dragon_temp->MvFloor[egw->FloorIdx];
			egw->MoveCount = 0;
			//回転ステート更新
			{
				DRAGON_GYM_WORK *dragon_gym_work;
				GIMMICKWORK *work;
				work = SaveData_GetGimmickWork(GameSystem_GetSaveData(fsys));
				dragon_gym_work = (DRAGON_GYM_WORK*)GIMMICKWORK_Get(work, FLD_GIMMICK_DRAGON_GYM);
				dragon_gym_work->RevState[ egw->FloorIdx ] =
					(dragon_gym_work->RevState[ egw->FloorIdx ]+1)%4;
				floor->RevState = dragon_gym_work->RevState[ egw->FloorIdx ];

				OS_Printf("回転ステート：%d\n",floor->RevState);
			}
			//座標群更新
			{
				int x,z;
				FIELD_OBJ_PTR fldobj;
				fldobj = Player_FieldOBJGet( fsys->player );
				x = FieldOBJ_NowPosGX_Get( fldobj );
				z = FieldOBJ_NowPosGZ_Get( fldobj );
				CalcRot(FLOOR_REV_90, x, z, floor);
#ifdef PM_DEBUG
				DebugPrint(floor);
#endif
			}
			egw->Seq = SEQ_REV_END;
		}
		break;
	case SEQ_REV_NG_ANM:
		{
			M3DO_PTR ptr;
			int entry;
			VecFx32 *rev;

			entry = dragon_temp->MvFloor[egw->FloorIdx].MdlIdx;
			ptr = M3DO_GetMap3DObjData(fsys->Map3DObjExp, entry);
			rev = M3DO_GetRotateVecPtr(ptr);
			rev->y += (-REV_VAL);
			//回転値を足しこむ
			egw->Rev += REV_VAL;

			if (egw->Rev >= egw->LimitRev){
				rev->y = egw->BaseRev - egw->LimitRev;
				egw->Seq = SEQ_REV_REVERS;
			}
		}
		break;
	case SEQ_REV_REVERS:
		{
			M3DO_PTR ptr;
			int entry;
			VecFx32 *rev;

			entry = dragon_temp->MvFloor[egw->FloorIdx].MdlIdx;
			ptr = M3DO_GetMap3DObjData(fsys->Map3DObjExp, entry);
			rev = M3DO_GetRotateVecPtr(ptr);
			rev->y += REV_VAL;
			//回転値をひく
			egw->Rev -= REV_VAL;

			if (egw->Rev <= 0){
				rev->y = egw->BaseRev;
				egw->Seq = SEQ_REV_END;
			}
		}
		break;
	case SEQ_REV_END:
		//SEストップ
		Snd_SeStopBySeqNo(SEQ_SE_GS_GONDORA_IDOU, 0);
		//ワーク解放
		sys_FreeMemoryEz(egw);
		return TRUE;
		break;
	}

	return FALSE;
}

//---------------------------------------------------------------------------
/**
 * @brief	回転における当たり判定
 *
 * @param	fsys		フィールドシステムポインタ
 * @param	floor		フロア
 * @param	outRot		回転格納バッファ
 *
 * @return	REV_RC		回転リターンコード
 */
//---------------------------------------------------------------------------
static REV_RC CheckHitRev(FIELDSYS_WORK * fsys, MV_FLOOR *floor, u16 *outRot)
{
	u8 left_loop;
	u8 rc;

	u16 rot;

	left_loop = floor->GridW - 1;

	//回転がまったく起こらないかを調べる
	{
		//前方
		rc = CheckHit(fsys, floor->GridW, floor->SideFront);
		if (rc!=HIT_NONE){
			return REV_NONE;
		}
		//後方
		rc = CheckHit(fsys, floor->GridW, floor->SideBack);
		if (rc!=HIT_NONE){
			return REV_NONE;
		}
		//右側面
		rc = CheckHit(fsys, floor->GridH, floor->SideRight);
		if (rc!=HIT_NONE){
			return REV_NONE;
		}
		//左側面
		rc = CheckHit(fsys, left_loop, floor->SideLeft);
		if (rc!=HIT_NONE){
			return REV_NONE;
		}
	}
	//ちょっと回転するかを調べる
	rot = GetRevHitVal( fsys, floor );

	if (rot < 0x4000){
		*outRot = rot;
		return REV_NG;
	}
	return REV_OK;
}

//---------------------------------------------------------------------------
/**
 * @brief	回転しようとしたとき、何度でヒットするかを判定する関数
 *
 * @param	fsys		フィールドシステムポインタ
 * @param	floor		フロア
 *
 * @return	u16		回転値
 */
//---------------------------------------------------------------------------
static u16 GetRevHitVal( FIELDSYS_WORK * fsys, MV_FLOOR *floor )
{
	u8 loop_f,loop_b;
	u16 rot_f, rot_b, rot;
	const u8 *check_array_f;
	const u8 *check_array_b;

	if (floor->Type == FLOOR_TYPE_1){
		loop_f = (TYPE1_FRONT_LEN-TYPE1_RIGHT_LEN)*TYPE1_H;
		check_array_f = RevInfoFront1;
		check_array_b = RevInfoBack1;
	}else{
		loop_f = (TYPE2_FRONT_LEN-TYPE2_RIGHT_LEN)*TYPE2_H;
		check_array_f = RevInfoFront2;
		check_array_b = RevInfoBack2;
	}

	loop_b = floor->GridW;

	rot_f = CheckAffHit(fsys, loop_f, floor->RevAffectGrid, check_array_f);

	rot_b = CheckAffHit(fsys, loop_b, floor->RevAffBackGrid, check_array_b);

	//小さい方を採用
	if (rot_f>rot_b){
		rot = rot_b;
	}else{
		rot = rot_f;
	}

	return rot;
}

//---------------------------------------------------------------------------
/**
 * @brief	移動TCB
 *
 * @param	tcb			TCBポインタ
 * @param	work		ワークポインタ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
static void ShiftTcb( TCB_PTR tcb, void *work )
{
	EVENT_GYM_WORK * egw = work;
	FIELDSYS_WORK * fsys = egw->fsys;
	DRAGON_GYM_TEMP_WORK *dragon_temp = (DRAGON_GYM_TEMP_WORK *)fsys->fldmap->Work;

	switch(egw->Seq){
	case SEQ_SHIFT_CHECK:
		{
			BOOL hit;
			egw->MoveCount = 0;
			//コピーデータを使って1グリッド幅分のヒットをチェックしてみる
			hit = CheckHit(fsys, dragon_temp->MvFloor[egw->FloorIdx].GridH, egw->SideTemp);
			//もしいけるなら、アニメ開始
			if (hit == HIT_NONE){	//いける
				egw->Seq = SEQ_SHIFT_ANM;
			}else {	//無理(途中いけなくなったら、ぶつかったアニメシーケンスへ)
				egw->Seq = SEQ_HIT_ACTION_SET;
			}
		}
		break;
	case SEQ_SHIFT_ANM:
		{
			FIELD_OBJ_PTR fldobj;
			//アニメ
			{
				M3DO_PTR ptr;
				int entry;
				VecFx32 lift_vec;

				entry = dragon_temp->MvFloor[egw->FloorIdx].MdlIdx;
				ptr = M3DO_GetMap3DObjData(fsys->Map3DObjExp, entry);
				lift_vec = M3DO_GetGlobalVec(ptr);
				VEC_Add(&lift_vec , &egw->MoveVec, &lift_vec);
				//リフト座標更新
				M3DO_SetGlobalVec(ptr, &lift_vec);
				//自機の座標セット
				{
					VecFx32 player_vec;
					fldobj = Player_FieldOBJGet( fsys->player );
					FieldOBJ_VecPosGet( fldobj, &player_vec );
					VEC_Add(&player_vec , &egw->MoveVec, &player_vec);
					FieldOBJ_VecPosSet( fldobj, &player_vec );
				}
			}

			if (++egw->MoveCount >= MOVE_COUNT){
				egw->MoveCount = 0;
				//アニメ終わったら、コピーデータ更新
				AddSideTmpInfo(dragon_temp->MvFloor[egw->FloorIdx].GridH, egw);

				egw->AnmCount++;
				//移動回数分繰り返す
				if (egw->AnmCount >= egw->AnmCountMax){
					//自機グリッド座標更新
					{
						VecFx32 player_vec;
						FieldOBJ_VecPosGet( fldobj, &player_vec );
						FieldOBJ_NowPosGX_Set( fldobj, player_vec.x/(FX32_ONE*ONE_GRID_SIZE) );
						FieldOBJ_NowPosGZ_Set( fldobj, player_vec.z/(FX32_ONE*ONE_GRID_SIZE) );
						FieldOBJ_GPosUpdate( fldobj );
					}
					//タスク削除
					TCB_Delete(tcb);
					egw->Seq = SEQ_SHIFT_UPDATE;
				}else{
					//チェックシーケンス
					egw->Seq = SEQ_SHIFT_CHECK;
				}
			}
		}
		break;
	case SEQ_HIT_ACTION_SET:
		//ぶつかったＳＥ
		Snd_SePlay(SEQ_SE_GS_GONDORA_KABEHIT);
		egw->Seq = SEQ_HIT_ACTION;
		break;
	case SEQ_HIT_ACTION:
		//アニメおわったら引き返しアニメ
		if (1){
			//移動したかで分岐
			if (egw->AnmCount == 0){
				//タスク削除
				TCB_Delete(tcb);

				egw->Seq = SEQ_SHIFT_END;
			}else{
				//移動方向を逆にする
				egw->MoveVec.x *= (-1);
				egw->MoveVec.z *= (-1);
				egw->Seq = SEQ_SHIFT_REVERS;
			}
		}
		break;
	case SEQ_SHIFT_REVERS:
		//アニメ終了後引き換えしシーケンスへ（ヒッチはいらんよ）
		{
			M3DO_PTR ptr;
			int entry;
			VecFx32 lift_vec;
			FIELD_OBJ_PTR fldobj;

			entry = dragon_temp->MvFloor[egw->FloorIdx].MdlIdx;
			ptr = M3DO_GetMap3DObjData(fsys->Map3DObjExp, entry);
			lift_vec = M3DO_GetGlobalVec(ptr);
			VEC_Add(&lift_vec , &egw->MoveVec, &lift_vec);
			//リフト座標更新
			M3DO_SetGlobalVec(ptr, &lift_vec);

			//自機の座標セット
			{
				VecFx32 player_vec;
				fldobj = Player_FieldOBJGet( fsys->player );
				FieldOBJ_VecPosGet( fldobj, &player_vec );
				VEC_Add(&player_vec , &egw->MoveVec, &player_vec);
				FieldOBJ_VecPosSet( fldobj, &player_vec );
			}
		}

		if (++egw->MoveCount >= MOVE_COUNT){
			egw->MoveCount = 0;
			egw->AnmCount--;
			//移動回数分繰り返す
			if (egw->AnmCount == 0){
				//タスク削除
				TCB_Delete(tcb);
				egw->Seq = SEQ_SHIFT_END;
			}
		}
		break;
	}
}

#ifdef PM_DEBUG
static void DebugPrint(MV_FLOOR *floor)
{
	u8 loop;
	int n;

	OS_Printf("左側：\n");
	for(n=0;n<floor->GridH;n++){
		OS_Printf("%d,%d\n",floor->SideLeft[n].X, floor->SideLeft[n].Z);
	}
	OS_Printf("右側：\n");
	for(n=0;n<floor->GridH;n++){
		OS_Printf("%d,%d\n",floor->SideRight[n].X, floor->SideRight[n].Z);
	}
	OS_Printf("前方：\n");
	for(n=0;n<floor->GridW;n++){
		OS_Printf("%d,%d\n",floor->SideFront[n].X, floor->SideFront[n].Z);
	}
	OS_Printf("後方：\n");
	for(n=0;n<floor->GridW;n++){
		OS_Printf("%d,%d\n",floor->SideBack[n].X, floor->SideBack[n].Z);
	}
	OS_Printf("回転影響：\n");

	if (floor->Type == FLOOR_TYPE_1 ){
		loop = (TYPE1_FRONT_LEN-TYPE1_RIGHT_LEN)*TYPE1_H;
	}else{
		loop = (TYPE2_FRONT_LEN-TYPE2_RIGHT_LEN)*TYPE2_H;
	}
	for(n=0;n<loop;n++){
		OS_Printf("%d,%d\n",floor->RevAffectGrid[n].X, floor->RevAffectGrid[n].Z);
	}
	for(n=0;n<floor->GridW;n++){
		OS_Printf("%d,%d\n",floor->RevAffBackGrid[n].X, floor->RevAffBackGrid[n].Z);
	}
}

static VecFx32 debug_vec;
static int debug_rev_val;
#define DEBUG_REV_VAL	(0x80)
#define DEBUG_REV_VAL2	(0x100)

static BOOL DebugFloorEvent( GMEVENT_CONTROL * event )
{
	DRAGON_GYM_TEMP_WORK *dragon_temp;
	FIELDSYS_WORK * fsys = FieldEvent_GetFieldSysWork(event);
	EVENT_GYM_WORK * egw = FieldEvent_GetSpecialWork(event);

	dragon_temp = (DRAGON_GYM_TEMP_WORK *)fsys->fldmap->Work;

	switch(egw->Seq){
	case 0:
		debug_vec.x = 0;
		debug_vec.y = 0;
		debug_vec.z = 0;
		//キー検出
		if (sys.trg & PAD_KEY_UP){
			debug_vec.z = -(ONE_GRID_SIZE*FX32_ONE);
			egw->Seq = 1;
		}else if(sys.trg & PAD_KEY_DOWN){
			debug_vec.z = (ONE_GRID_SIZE*FX32_ONE);
			egw->Seq = 1;
		}else if (sys.trg & PAD_KEY_LEFT){
			debug_vec.x = -(ONE_GRID_SIZE*FX32_ONE);
			egw->Seq = 1;
		}else if (sys.trg & PAD_KEY_RIGHT){
			debug_vec.x = (ONE_GRID_SIZE*FX32_ONE);
			egw->Seq = 1;
		}

		else if (sys.cont & PAD_BUTTON_R){
			debug_rev_val = DEBUG_REV_VAL;
			egw->Seq = 3;
		}else if(sys.trg & PAD_BUTTON_A){
			debug_rev_val = DEBUG_REV_VAL;
			egw->Seq = 3;
		}else if(sys.trg & PAD_BUTTON_Y){
			debug_rev_val = DEBUG_REV_VAL2;
			egw->Seq = 3;
		}else if(sys.trg & PAD_BUTTON_X){
			debug_rev_val = 0x4000;
			egw->Seq = 3;
		}else if(sys.trg & PAD_BUTTON_B){
			egw->Seq = 4;
		}

		break;
	case 1:							//平行移動
		{
			FIELD_OBJ_PTR fldobj;
			//アニメ
			{
				M3DO_PTR ptr;
				int entry;
				VecFx32 lift_vec;
				entry = dragon_temp->MvFloor[egw->FloorIdx].MdlIdx;
				ptr = M3DO_GetMap3DObjData(fsys->Map3DObjExp, entry);
				lift_vec = M3DO_GetGlobalVec(ptr);
				VEC_Add(&lift_vec , &debug_vec, &lift_vec);
				//リフト座標更新
				M3DO_SetGlobalVec(ptr, &lift_vec);
				//自機の座標セット
				{
					VecFx32 player_vec;
					fldobj = Player_FieldOBJGet( fsys->player );
					FieldOBJ_VecPosGet( fldobj, &player_vec );
					VEC_Add(&player_vec , &debug_vec, &player_vec);
					FieldOBJ_VecPosSet( fldobj, &player_vec );
					//自機グリッド座標更新
					FieldOBJ_VecPosGet( fldobj, &player_vec );
					FieldOBJ_NowPosGX_Set( fldobj, player_vec.x/(FX32_ONE*ONE_GRID_SIZE) );
					FieldOBJ_NowPosGZ_Set( fldobj, player_vec.z/(FX32_ONE*ONE_GRID_SIZE) );
					FieldOBJ_GPosUpdate( fldobj );
				}
			}
			egw->Seq = 2;
		}
		break;
	case 2:
		//フィールドOBJの更新を1シンク待つシーケンス
		egw->Seq = 0;
		break;
	case 3:			//回転
		{
			M3DO_PTR ptr;
			int entry;
			VecFx32 *rev;

			entry = dragon_temp->MvFloor[egw->FloorIdx].MdlIdx;
			ptr = M3DO_GetMap3DObjData(fsys->Map3DObjExp, entry);
			rev = M3DO_GetRotateVecPtr(ptr);
			rev->y += (-debug_rev_val);
			egw->Seq = 0;

			//回転角表示
			{
				u16 rad = rev->y;
				OS_Printf("vec__rad = %x,%x\n", rev->y,rad);
			}
		}
		break;
	case 4:	//回転リセット
		{
			M3DO_PTR ptr;
			int entry;
			VecFx32 *rev;

			entry = dragon_temp->MvFloor[egw->FloorIdx].MdlIdx;
			ptr = M3DO_GetMap3DObjData(fsys->Map3DObjExp, entry);
			rev = M3DO_GetRotateVecPtr(ptr);
			rev->y = 0;
			egw->Seq = 0;
			//回転角表示
			{
				u16 rad = rev->y;
				OS_Printf("vec__rad = %x,%x\n", rev->y,rad);
			}
		}
		break;
	}

	return FALSE;
}

#endif //PM_DEBUG